///////////////////////////////////////////////////////////////////////////////
////  (c) Chaichuk AU (chaichuk@mail.ru), 								   ////
////  2004, Chelyabinsk, NTC Privodnaya Tehnika (momentum@chel.surnet.ru)  ////
///////////////////////////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include "../api.h"
#include "iofuncs.h"
#include "plc_io.h"

int
io_devctl (resmgr_context_t *ctp, io_devctl_t *msg, RESMGR_OCB_T *ocb)
{
	int					sts;
	void				*data;
	int					nbytes;
	int					dcmd;
	int					len;
	mem_data_t*			mem_data;	
	int					ret_code = 0;
	int					retry_count;
	
/*
 *	WARNING:  check in main.c to see if you need to adjust the "nparts_max" and "msg_max_size"
*/


	// see if it's a standard POSIX-supported devctl()
	if ((sts = iofunc_devctl_default (ctp, msg, ocb)) != _RESMGR_DEFAULT) {
		return (sts);
	}

	// assign a pointer to the data area of the message
	data = _DEVCTL_DATA (*msg);

	// get other data that can't be wiped out before we wipe the data structure
	dcmd = msg -> i.dcmd;
	len = msg -> i.nbytes;
	memset (&msg -> o, 0, sizeof (msg -> o));

	// preset the number of bytes that we'll return to zero
	nbytes = 0;

	// check for all commands
	switch (dcmd) {

	case DCMD_READ_MEM:

		mem_data = (mem_data_t *) data;
		retry_count = 0;
		do {
			ret_code = memory_read (mem_data->code, mem_data->addr, mem_data->n_elem, mem_data->data);
			retry_count ++;			
		} while (ret_code < 0 && retry_count < mem_data->retry_max);
		if (ret_code < 0) fprintf (stderr, "dummy_FINS read failure !!!\n");
		mem_data->ret_code = ret_code;
		nbytes = sizeof (mem_data_t);
		break;

	case DCMD_WRITE_MEM:

		mem_data = (mem_data_t *) data;
		retry_count = 0;
		do {
			ret_code = memory_write (mem_data->code, mem_data->addr, mem_data->n_elem, mem_data->data);
			retry_count ++;			
		} while (ret_code < 0 && retry_count < mem_data->retry_max);
		if (ret_code < 0) fprintf (stderr, "dummy_FINS write failure !!!\n");
		mem_data->ret_code = ret_code;
		nbytes = sizeof (mem_data_t);
		break;
	
	default:
		return (ENOSYS);
	}

	// return data (if any) to the client
	msg -> o.nbytes = nbytes;
	SETIOV (ctp -> iov, &msg -> o, sizeof (msg -> o) + nbytes);
	return (_RESMGR_NPARTS (1));
}